import { Plugin, AllPlugin } from '../plugins/Plugin';

export type GetProps<T> = T extends UsePlugin<infer U, any> ? U : never;
export type GetState<T> = T extends UsePlugin<any, infer U> ? U : never;

export class UsePlugin<Props = {}, State = {}> {
  protected plugins: Array<[string | undefined, Plugin<any, any, any>]> = [];

  public use<P, S>(plugin: Plugin<any, P, S> | UsePlugin<P, S>): UsePlugin<Props & P, State & S>;
  public use<P, S>(plugin: UsePlugin<P, S>): UsePlugin<Props & P, State & S>;
  public use<P, S>(plugin: Plugin<any, P, S>, name?: string): UsePlugin<Props & P, State & S>;

  public use<P, S>(plugin: Plugin<any, P, S> | UsePlugin<P, S>, name?: string): UsePlugin<Props & P, State & S> {
    if (plugin instanceof UsePlugin) {
      plugin.plugins.forEach((item) => {
        const key = item[0];

        if (key !== undefined) {
          const position = this.plugins.findIndex((p) => p[0] === key);

          if (position >= 0) {
            this.plugins[position] = item;
            return;
          }
        }

        this.plugins.push(item);
      });
    } else if (name !== undefined) {
      this.plugins.push([name, plugin]);
    } else {
      this.plugins.push([name, plugin]);
    }

    return this;
  }

  public/*protected*/ getPlugins(): Plugin[] {
    return this.plugins.map((item) => item[1]);
  }
}

export function use<Props, State>(plugin: AllPlugin<Props, State> | UsePlugin<Props, State>): UsePlugin<Props, State>;
export function use<Props, State>(plugin: UsePlugin<Props, State>): UsePlugin<Props, State>;
export function use<Props, State>(plugin: AllPlugin<Props, State>, name?: string): UsePlugin<Props, State>;

export function use<Props, State>(plugin: any, name?: string): UsePlugin<Props, State> {
  return new UsePlugin().use(plugin, name);
};
